#pragma once

// 移植nginx的内存池模块，将其重构为C++代码
//

#include <cstddef>
#include <cstdlib>
#include <iostream>

// 大块内存的头部信息
struct ngx_pool_large_t {
    ngx_pool_large_t *next;
    void *alloc;  // 大块内存起始地址
};

typedef void (*ngx_pool_cleanup_pt)(void *data);
// 大块内存中的外部资源额外的资源清理操作
struct ngx_pool_cleanup_t {
    ngx_pool_cleanup_pt handler;  // 资源清理操作回调函数
    void *data;                   // 回调函数所需参数
    ngx_pool_cleanup_t *next;     // 下一个节点
};

struct ngx_pool_t;
// 小块内存池的头部信息
struct ngx_pool_data_t {
    unsigned char *last;  // 小块内存池可用内存起始地址
    unsigned char *end;   // 小块内存池可用内存末尾地址
    ngx_pool_t *next;     // 下一个内存池
    unsigned int failed;  // 当前所在内存池内存分配失败次数
};

// ngx内存池的头部信息
struct ngx_pool_t {
    ngx_pool_data_t d;
    size_t max;           // 区分小块内存和大块内存的阈值
    ngx_pool_t *current;  // 第一个可以提供小块内存分配的内存池
    ngx_pool_large_t *large;      // 大块内存头部信息链表头节点
    ngx_pool_cleanup_t *cleanup;  // 额外资源清理操作的头节点
};

#define ngx_memzero(buf, n) (void)memset(buf, 0, n)
// 将数值d调整为 邻近的a的整数倍
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
// 将指针p调整为 邻近的a的整数倍
#define ngx_align_ptr(p, a)                                           \
    (unsigned char *)(((unsigned long)(p) + ((unsigned long)a - 1)) & \
                      ~((unsigned long)a - 1))
#define NGX_ALIGNMENT sizeof(unsigned long)
const int ngx_pagesize = 4096;
const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;
const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;
const int NGX_POOL_ALIGNMENT = 16;
const int NGX_MIN_POOL_SIZE = ngx_align(
    (sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), NGX_POOL_ALIGNMENT);

// 移植nginx内存池的代码，基于OOP实现
class ngx_mem_pool {
public:
    ngx_mem_pool(size_t size = 1024) {
        if (!ngx_create_pool(size)) {
            std::cerr << "failed to initialize ngx_mem_pool." << std::endl;
        }
    }

    ~ngx_mem_pool() {
        ngx_destroy_pool();
    }

public:
    // 考虑内存字节对齐，从内存池中申请size大小的内存
    void *ngx_palloc(size_t size);

    // 不考虑内存字节对齐，从内存池中申请size大小的内存
    void *ngx_pnalloc(size_t size);

    // 同ngx_palloc，但是内存初始化为0
    void *ngx_pcalloc(size_t size);

    // 释放大块内存
    void ngx_pfree(void *p);

    // 内存重置函数
    void ngx_reset_pool();

    // 添加资源清理回调操作
    ngx_pool_cleanup_t *ngx_pool_cleanup_add(size_t size);

private:
    // 创建指定size大小的内存池， 但是小块内存不超过一个页面的大小
    bool ngx_create_pool(size_t size);

    // 内存池的销毁函数
    void ngx_destroy_pool();
    // 小块内存分配

    void *ngx_palloc_small(size_t size, unsigned int align);

    // 大块内存分配
    void *ngx_palloc_large(size_t size);

    // 分配新的小块内存池
    void *ngx_palloc_block(size_t size);

private:
    ngx_pool_t *_pool;  // 内存池入口地址
};
